#pragma once

// 模版也可以有缺省参数
// 函数参数传的是对象，模板传的是类型

namespace mystack
{
    template <class T, class Container = deque<T>>
    class stack
    {
    public:
        void push(const T &x)
        {
            _con.push_back(x);
        }
        void pop()
        {
            _con.pop_back();
        }
        const T &top()
        {
            return _con.back();
        }
        size_t size()
        {
            return _con.size();
        }
        bool empty()
        {
            return _con.empty();
        }

    private:
        Container _con;
    };
    void test_stack()
    {
        stack<int> s;

        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);

        while (!s.empty())
        {
            cout << s.top() << " ";
            s.pop();
        }
        cout << endl;
    }
    void test_stack1()
    {
        stack<int, list<int>> s;

        s.push(1);
        s.push(2);
        s.push(3);
        s.push(4);

        while (!s.empty())
        {
            cout << s.top() << " ";
            s.pop();
        }
        cout << endl;
    }

}

// 这种写法用了什么思想？
// 这种写法采用了模板编程和容器适配器的思想。
//
// 模板编程：通过使用模板参数，类stack能够适用于不同的数据类型和底层容器。
// 容器适配器：stack并不是从零开始实现数据存储，而是利用现有的标准容器（如deque）来实现其功能。这种方法减少了重复代码，提高了代码的重用性和可维护性。
// 为什么这样写？
// 灵活性：通过模板参数，用户可以自定义stack的底层容器类型，而不仅限于deque。这使得stack更为灵活和通用。
// 减少代码重复：利用现有的标准容器如deque、vector、list等，避免了重新实现基本的容器操作（如插入、删除等）。
// 提高效率：使用标准库中的容器通常可以提供高效和经过优化的实现。
// 为什么第二个模板参数是class Container = deque<T> ?
// 默认参数：class Container = deque<T>意味着Container默认使用deque<T>作为底层容器。如果用户没有指定第二个模板参数，stack将使用deque<T>作为其底层容器。
// 适应性：deque是一个双端队列，支持在两端进行快速的插入和删除操作，非常适合用作stack的底层容器。
// 模板参数也支持缺省值吗？
// 是的，模板参数支持缺省值。缺省值为模板提供了默认的行为，如果用户在实例化模板时没有提供某个模板参数，编译器将使用缺省值。
//
// 在你的代码中，class Container = deque<T>就是一个模板参数缺省值的例子。用户可以选择性地提供自己的容器类型，比如vector或list，也可以直接使用默认的deque<T>。
//
//
//
//
// 类模板stack的默认构造函数、析构函数、拷贝构造函数和赋值运算符重载函数都是由编译器自动生成的。因为类模板stack中的成员变量_con是一个容器对象（如std::deque），
// 而这些容器类本身已经提供了适当的构造、析构、拷贝和赋值操作，所以默认生成的函数能够正常工作。